package org.geekbang.thinking.in.spring.bean.definition;

import org.geekbang.thinking.in.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * 注解的 BeanDefinition 示例
 */
@Import(AnnotationBeanDefinitionDemo.Config.class)//通过 @Import 来进行导入
public class AnnotationBeanDefinitionDemo {

    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类)
        applicationContext.register(AnnotationBeanDefinitionDemo.class);

        //通过 BeanDefinition 注册 API 实现
        //1.命名 Bean 注册方式
        //1.1 如果名称与注解名称重复（bean名），不会报错，但是会覆盖掉注解Bean User
        //1.2 如果名称与注解名称重复（别名），不会报错，也不会覆盖掉注解Bean User，消失了
        registerBeanDefinition(applicationContext, "baiyunlong-user", User.class);

        //2. 非命名 Bean 的注册方法
        registerBeanDefinition(applicationContext, User.class);

        //启动 Spring 应用上下文(XML配置方式不需要)
        applicationContext.refresh();

        //依赖查找
        System.out.println("Config 类型的所有 Beans "+applicationContext.getBeansOfType(Config.class));
        System.out.println("User 类型的所有 Beans "+applicationContext.getBeansOfType(User.class));
        User user = applicationContext.getBean("baiyunlong-user", User.class);
        System.out.println(user);
        //显式的关闭 Spring 应用上下文
        applicationContext.close();
    }

    /**
     * 命名 Bean 的注册方式
     * @param registry
     * @param beanName
     * @param beanClass
     */
    public static void registerBeanDefinition(BeanDefinitionRegistry registry, String beanName, Class<?> beanClass){
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
        beanDefinitionBuilder
                .addPropertyValue("id", 2L)
                .addPropertyValue("name", "白云龙");

        if(StringUtils.hasText(beanName)){
            //注册 BeanDefinition
            registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
        }else{
            //非命名 Bean 注册方式
            BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), registry);
        }

    }

    public static void registerBeanDefinition(BeanDefinitionRegistry registry, Class<?> beanClass){
        registerBeanDefinition(registry, null, beanClass);
    }

    @Component // 2.通过 @Component 方式定义
    public static class Config{

        /**
         * 通过 Java  注解方式定义了一个 Bean
         * @return
         */
        @Bean(name = {"user", "baiyunlong-user"})//1.通过 @Bean 方式定义
        public User user(){
            User user = new User();
            user.setId(1L);
            user.setName("白云龙");
            return user;
        }
    }


}
